<?php

namespace App\Models\Traits;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use App\Helpers\QueryHelp;

trait QueryFilters
{
    protected $sort = [];    //默认排序
    protected $sorts = [];              //允许排序字段
    protected $includes = [];           //允许使用关联
    protected $filters = [];            //允许过滤字段，空则为排除$hiddenFilters外的字段
    protected $hiddenFilters = [];      //指定不允许过滤字段，空则为所有visable字段
    protected $fields = [];             //检索时可显示字段，空则为排除hidden和hiddenFields的所有
    protected $hiddenFields = [];       //指定不显示在列表中字段,已在hidden中设定的无需包括

    protected $withSet = [];            //with设置
    protected $queryInit = [];            //查询初始设置

    public function setSort(array $sorts)
    {
        return $this->sort;
    }
    public function getSort()
    {
        return $this->sort ?: ['-created_at'];
    }
    public function setSorts(array $sorts)
    {
        $this->sorts = $sorts;
    }
    public function getSorts(array $sorts)
    {
        return $this->sorts;
    }

    public function setIncludes(array $includes)
    {
        $this->includes = $includes;
    }
    public function getIncludes()
    {
        return $this->includes;
    }
    public function setFilters(array $filters)
    {
        $this->filters = $filters;
    }

    public function getFilters()
    {
        if ($this->filters) {
            $filters = array_intersect($this->getTableFields(), $this->filters);
            return array_diff($filters, $this->hiddenFilters);
        } else {
            return array_diff($this->getTableFields(), $this->hiddenFilters);
        }
    }

    public function setHiddenFilters(array $filters)
    {
        $this->hiddenFilters = $filters;
    }

    public function getHiddenFilters()
    {
        return $this->hiddenHilters;
    }

    public function setFields(array $fields)
    {
        $this->fields = $fields;
    }

    public function getFields()
    {
        if ($this->fields) {
            return array_intersect($this->getAllowedFields(), $this->fields);
        } else {
            return array_diff($this->getAllowedFields(), $this->hiddenFields);
        }
    }

    public function setHiddenFields(array $fields)
    {
        $this->hiddenFields = $fields;
    }
    public function getHiddenFields()
    {
        return $this->hiddenFields;
    }

    /**
     * 关联设置添加
     * @$set array
     */
    public function setWithSet(array $set)
    {
        $this->withSet = $set;
    }
    public function getWithSet($name = '')
    {
        if (!empty($this->withSet[$name])) {
            return $this->withSet[$name];
        } else {
            return ['query' => 0];
        }
    }

    public function setQueryInit(array $set)
    {
        $this->queryInit = $set;
    }
    public function getQueryInit()
    {
        return $this->queryInit;
    }

    //所有字段
    public function getAllFields()
    {
        return array_merge($this->getTableFields(), $this->appends);
    }

    /**
     * 模型所有可显示字段
     */
    public function getAllowedFields()
    {
        if ($this->getVisible()) {
            return $this->getVisible();
        } else {
            return array_diff($this->getAllFields(), $this->hidden);
        }
    }


    /**
     * allQuery全检索
     *
     * @Author 老蟹 7040867@qq.com    DateTime 2020-01-12
     * @param Builder|model $query
     * @param array|null $q
     * @return $query
     */
    function ScopeAllQuery($query, $q = null)
    {
        $includes = $this->getIncludes();

        if (is_null($q)) {
            $q = request()->all();
            //仅在request时使用预设
            if ($listset = $this->getQueryInit()) $q = array_merge($listset, $q);
            $page_type = $q['page_type'] ?? 0;
        } else {
            $page_type = $q['page_type'] ?? 2;
        }
        if (empty($q) || !is_array($q)) $q = [];

        $def_fields = $this->getFields();  //默认字段

        $fields = array_intersect(str2arr($q['fields'] ?? ''), $def_fields);
        $fields = $fields ?: $def_fields;
        $query  = $query->select($fields);

        $filters = $this->getFilters();  //主查询允许查询字段
        $query  = QueryHelp::filter($query, $q, $filters);

        $with_query = [];
        $withsets   = [];
        foreach ($includes as $key => $value) {
            $withsets[$value] = $this->getWithSet($value);
            if (!empty($withsets[$value]['query'])) $with_query[] = $value;
        }

        $withs = [];
        $q['include'] = array_intersect(str2arr($q['include'] ?? ''), $includes);
        if (!empty($q['include'])) {
            foreach ($q['include'] as $key => $with) {   //使用with的关联
                $set = $withsets[$with];
                $fields = str2arr($set['fields'] ?? '');
                $hidden = str2arr($set['hidden_fields'] ?? '');
                $select = $q['with'][$with]['fields'] ?? '';
                $sort   = $q['with'][$with]['sort'] ?? ($set['sort'] ?? '');
                $limit  = $q['with'][$with]['limit'] ?? '';
                $limit  = $limit ?: ($set['limit'] ?? 0);
                if ($select) {
                    $select = array_diff(str2arr($select), $hidden);
                } else {
                    $select = $fields;
                }

                $withs[$with] = function ($query) use ($select, $sort, $limit, $set) {
                    if (!empty($select)) {
                        $query = $query->select($select);
                    }
                    //以下仅对一对多查询
                    if (!empty($set['query'])) {
                        //这个意义不大
                        if (!empty($limit)) {
                            $query = $query->limit($limit);
                        }
                        if (!empty($sort)) {
                            $query = QueryHelp::sort($query, $sort);
                        }
                    }
                };
            }
        }
        if (!empty($withs)) {
            $query = $query->with($withs);
        }

        if (!empty($q['scope']) && is_array($q['scope'])) {
            foreach ($q['scope'] as $k => $v) {
                $method = Str::camel('scope_' . $k);
                $scope = Str::camel($k);
                if (method_exists($this, $method)) {
                    $param = ($v == '@') ? [] : explode(',', $v);
                    $param = array_map(function ($val) {
                        if (strpos($val, 'in:') === 0) {
                            return explode('|', substr($val, 3));
                        } else {
                            return $val;
                        }
                    }, $param);
                    $query = QueryHelp::scope($query, $scope, $param);
                }
            }
        }

        if (!empty($q['has']) && is_array($q['has'])) {
            $q_with = array_intersect_key($q['has'], array_flip($includes));
            $query = QueryHelp::has($query, $q_with);
        }

        if (!empty($q['orhas']) && is_array($q['orhas'])) {
            $q_with = array_intersect_key($q['orhas'], array_flip($includes));
            $query = QueryHelp::has($query, $q_with, true);
        }

        if (!empty($q['wherehas']) && is_array($q['wherehas'])) {
            $q_with = array_intersect_key($q['wherehas'], array_flip($with_query));
            if (!empty($q_with)) {
                foreach ($q_with as $key => $value) {
                    $fields = str2arr($withsets[$key]['filters'] ?? []);
                    $query = $query->whereHas($key, function (Builder $query) use ($value, $fields) {
                        $query = filter($query, $value, $fields);
                    });
                }
            }
        }

        if (!empty($q['orwherehas']) && is_array($q['orwherehas'])) {
            $q_with = array_intersect_key($q['orwherehas'], array_flip($with_query));
            if (!empty($q_with)) {
                foreach ($q_with as $key => $value) {
                    $fields = str2arr($withsets[$key]['filters'] ?? []);
                    $query = $query->orWhereHas($key, function (Builder $query) use ($value, $fields) {
                        $query = QueryHelp::filter($query, $value, $fields);
                    });
                }
            }
        }

        if (!empty($q['withcount']) && is_array($q['withcount'])) {
            $q_with = array_intersect_key($q['withcount'], array_flip($with_query));
            if (!empty($q_with)) {
                foreach ($q_with as $key => $value) {
                    $fields = str2arr($withsets[$key]['filters'] ?? []);
                    $query = $query->withCount([$key, $key => function (Builder $query) use ($value, $fields) {
                        $query = QueryHelp::filter($query, $value, $fields);
                    }]);
                }
            }
        }

        $sort = $q['sort'] ?? '';
        $sort = $sort ?: $this->getSort();
        if (!empty($sort)) {
            $query = QueryHelp::sort($query, $sort);
        } else {
            $query = $query->latest();
        }

        if ($page_type == 2) {
            $page = $q['page'] ?? 1;
            $limit = $q['limit'] ?? 10;
            $data = $query->offset($limit * ($page - 1))->limit($limit)->get();
            return $data;  //直接数据返回
        } else {
            return $query;
        }
    }
}
